//refs[0]
#define MPC_ORB 1
#define JPL_ORB 2

//refs[1]
#define PROPSYN     1
#define PROPANA     2

//refs[2]
#define DAVIDN      1
#define MILANI      2

//refs[3]
#define MASIERO11   1
#define MASIERO12   2
#define MASIERO14   4
#define NUGENT14    8
#define USUI14     16
#define TEDESCO02  32
#define NUGENT16   64
#define VICTOR    128

//refs[4] Extended D and pV

//refs[5]
#define BUSDEMEO     1
#define BUSBINZEL    2
#define SMASS2       4
#define THOLEN       8
#define BARUCCI     16
#define S3OS2       32
#define TEDESCOTAX  64
#define PINILLA16  128
#define DELEON16   256

//refs[6]
#define DEMEOCARRY   1
#define CARVANO      2
#define HOWELL       4

//refs[7]
#define ALCDEF       1
#define DAMIT        2
#define LOWELLPOLE   4

class Asteroid{
public:
  long Number;
  char Designation[20];
  char pack[10];
  char EpochPack[10];
  float H;
  float G;
  double a, e, sini, M, omega, Omega, n, Epoch;
  float neaSourceRegion[10];

  float H_1;
  float G1, G2;

  float H_2;
  float G12;

  unsigned char isBinary;
  
  float rotationPeriod;

  unsigned char refs[20]; // each byte is a different parameter

  unsigned int orbitalType; // 1 Aten; 2 Apollo; 4 Amor; 8 PHA; 16 MarsCrosser; 32 MBA; 

  void reset()
  {
    Number=0;
    isBinary=H_1=H_2=G1=G2=H_2=G12=H=G=e=a=sini=M=omega=Omega=n=Epoch=0;
    rotationPeriod=0;
    memset(Designation, 0, 20);
    memset(pack,0,10);
    memset(EpochPack,0,10);
    memset(refs,0,20);
    //    memset(neaSourceRegion, 0, 10*sizeof(neaSourceRegion[0]));
    resetNEAsSourceRegions();
  };
  
  Asteroid()
  {
    reset();
  };
  
  Asteroid(long Num, char Des[], double _a, double _e, double _sini)
  {
    reset();
    Number=Num;
    strcpy(Designation,Des);
    a=_a;
    e=_e;
    sini=_sini;
  };

  Asteroid(string line)
  {
    reset();
    this->MPCstring2elem(line);
  };
  
  void MPCstring2elem(string line)
  {
    //    sscanf(&line.at(0), "%s %lf %lf %5s %lf %lf %lf %lf %lf %lf %lf", 
    //	   pack, &H, &G, EpochPack, &M, &omega, &Omega, &i, &e, &n, &a);
    strncpy(pack,&line.at(0),7); pack[7]=0;
    H=atof(&line.at(8));
    G=atof(&line.at(15));
    strncpy(EpochPack,&line.at(20),5); EpochPack[5]=0;
    M=atof(&line.at(26));
    omega=atof(&line.at(37));
    Omega=atof(&line.at(48));
    sini=sin(3.1416*atof(&line.at(59))/180.0);
    e=atof(&line.at(70));
    a=atof(&line.at(92));
    // remove spaces while copying designation string
    char *write = Designation;
    char *read = &line.at(175);
    int j=0;
    do {
      if (*read != ' ')
	*write++ = *read;
    } while ((*read++) && ((++j)<19));
    *write++ =0;
    //strncpy(Designation,&line.at(175),19);
    Designation[19]=0;
      
    //    this->MPC2DesignationCompact();
    this->MPC2Number();
    this->MPC2Epoch();
  };

  void importMPC(string line)
  {
  };

  void print()
  {
    printf("%06ld %20s %10s %5.2lf %5.2lf %7.4lf %7.4lf %7.4lf\n", Number, Designation, pack, H, G, a, e, sini);
  };

  void MPC2Number()
  {	
    long k=(long)pack[0];
    char isnum=(short)pack[5];
    
    Number = -1;
    if (isnum>32) return;	// unnumbered object
    if (pack[4]>57) return;     // this is not a mumber but it may be natural satellite
    //    if (strlen(pack)>5) return;
    
    if ((k>=65) && (k<=90))  k-=55; // A-Z
    if ((k>=48) && (k<=57))  k-=48; // 0-9 
    if ((k>=97) && (k<=122)) k-=61; // a-z
    
    k*=10000;
    Number=(k+atol(&pack[1]));
  };

  void MPC2Designation()
  {	
    int k=(int)pack[0];
    int m=(int)pack[4];
    char CycleCountString[3];
    int CycleCount;
    
    if (strlen(pack)==5)  // this is a number 
      {
	this->MPC2Number();
	sprintf(Designation,"%ld",Number);
	return ;
      }

    strncpy(CycleCountString, &pack[4], 2); CycleCountString[3]=0;
    CycleCount=atoi(CycleCountString);  

    /*
      if (k>=65) k-=55; else k-=48;
      if (m>=65) m-=55; else m-=48;
    */
    if ((k>=65) && (k<=90))  k-=55;
    if ((k>=48) && (k<=57))  k-=48;
    if ((k>=97) && (k<=122)) k-=61;
    if ((m>=65) && (m<=90))  m-=55;
    if ((m>=48) && (m<=57))  m-=48;
    if ((m>=97) && (m<=122)) m-=61;
    
    //  printf("%s %d\n",CycleCountString,CycleCount);
    
    if (pack[4]<58) // the first cycle count digit is a number: so cycle count <=99
      {
	if (CycleCount==0)
	  sprintf(Designation,"%2d%c%c %c%c",k,pack[1],pack[2],pack[3],pack[6]);
	else
	  sprintf(Designation,"%2d%c%c %c%c%d",k,pack[1],pack[2],pack[3],pack[6],CycleCount);
	return;
      }
    else { // the first cycle count digit is a LETTER: so decodes it
      CycleCount=((int)pack[4]-65)*10+100+((int)pack[5]-48); 
      if (CycleCount>359) // it uses small letters
	CycleCount=((int)pack[4]-97)*10+360+((int)pack[5]-48); 
      sprintf(Designation,"%2d%c%c %c%c%d",k,pack[1],pack[2],pack[3],pack[6],CycleCount);
    }
    
    return;
  };

  void MPC2DesignationCompact()
  {
    int k=(int)pack[0];
    int m=(int)pack[4];
    char CycleCountString[3];
    int CycleCount;

    //    cout << strlen(pack) << "-" << pack << "-"<< endl;
    if (strlen(pack)==5)  // this is a number 
      {
	this->MPC2Number();
	sprintf(Designation,"%ld",Number);
	return;
      }
    
    strncpy(CycleCountString, &pack[4], 2); CycleCountString[3]=0;
    CycleCount=atoi(CycleCountString);  
    /*
      if (k>=65) k-=55; else k-=48;
      if (m>=65) m-=55; else m-=48;
    */
    if ((k>=65) && (k<=90))  k-=55;
    if ((k>=48) && (k<=57))  k-=48;
    if ((k>=97) && (k<=122)) k-=61;
    if ((m>=65) && (m<=90))  m-=55;
    if ((m>=48) && (m<=57))  m-=48;
    if ((m>=97) && (m<=122)) m-=61;

    //  printf("%s %d\n",CycleCountString,CycleCount);
    
    if (pack[4]<58) // the first cycle count digit is a number: so cycle count <=99
      {
	if (CycleCount==0)
	  sprintf(Designation,"%2d%c%c%c%c",k,pack[1],pack[2],pack[3],pack[6]);
	else
	  sprintf(Designation,"%2d%c%c%c%c%d",k,pack[1],pack[2],pack[3],pack[6],CycleCount);
	return ;
      }
    else { // the first cycle count digit is a LETTER: so decodes it
      CycleCount=((int)pack[4]-65)*10+100+((int)pack[5]-48); 
      if (CycleCount>359) // it uses small letters
	CycleCount=((int)pack[4]-97)*10+360+((int)pack[5]-48); 
      sprintf(Designation,"%2d%c%c%c%c%d",k,pack[1],pack[2],pack[3],pack[6],CycleCount);
    }
    return;
  };

  void slaCldj ( int iy, int im, int id, double *djm, int *j )
  {
   long iyL, imL;

   /* Month lengths in days */
   static int mtab[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };



   /* Validate year */
   if ( iy < -4699 ) { *j = 1; return; }

   /* Validate month */
   if ( ( im < 1 ) || ( im > 12 ) ) { *j = 2; return; }

   /* Allow for leap year */
   mtab[1] = ( ( ( iy % 4 ) == 0 ) &&
	     ( ( ( iy % 100 ) != 0 ) || ( ( iy % 400 ) == 0 ) ) ) ?
             29 : 28;

   /* Validate day */
   *j = ( id < 1 || id > mtab[im-1] ) ? 3 : 0;

   /* Lengthen year and month numbers to avoid overflow */
   iyL = (long) iy;
   imL = (long) im;
   
   /* Perform the conversion */
   *djm = (double)
     ( ( 1461L * ( iyL - ( 12L - imL ) / 10L + 4712L ) ) / 4L
       + ( 306L * ( ( imL + 9L ) % 12L ) + 5L ) / 10L
       - ( 3L * ( ( iyL - ( 12L - imL ) / 10L + 4900L ) / 100L ) ) / 4L
       + (long) id - 2399904L );
  };

  void MPC2Epoch()
  {
    int	year = (int)EpochPack[0];
    int dec;
    int month =(int)EpochPack[3];
    int	day	=(int)EpochPack[4];
    int	status;
    
    year=(year-55)*100;
    if ((sscanf(&EpochPack[1], "%2d", &dec))!=1)
      {
	Epoch=0;	// failed
	return;
      }
    year+=dec;
    
    if (month >= 65) month-=55; else month-=48;
    if (day >= 65) day-=55; else day-=48;
    
    this->slaCldj(year, month, day, &Epoch, &status );	// SLALIB fucntion
    if (status !=0) Epoch=0;
    Epoch+=2400000.5;	 
  };

  void designation2pack()
  {
    if (strlen(Designation)<1)
      {
	memset(pack,0,10);
	return;
      }
    
    char *read = Designation;
    char desCompact[20];  
    char *write;
    int  isSurvey=0;

    write=desCompact;
    // compact the designation by removing spaces or the underscore
    // remove spaces
    do {
      if ((*read != ' ') && (*read != '_')) 
	*write++ = *read;
      if (*read == '-')
	isSurvey=1;
    } while (*read++); // until a NULL is found

    // see
    //http://www.minorplanetcenter.net/iau/info/PackedDes.html
    unsigned int cent;
    unsigned int year;
    int cycle;
    char cycleLetter[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    // scan for Survey Designation
    //  Survey designations of the form 2040 P-L, 3138 T-1, 1010 T-2 and 4101 T-3 are packed differently.
    //  Columns 1-3 contain the code indicating the survey and columns 4-7 contain the number within the survey.
 
    if (isSurvey)
      {
	//      printf("survey\n");
	sscanf(desCompact,"%4d",&cycle);
	if (strncmp(&desCompact[4],"P-L",3)==0) // Palomar-Leiden survey
	  sprintf(pack,"PLS%04d",cycle);
	if (strncmp(&desCompact[4],"T-1",3)==0) // First Trojan Survey
	  sprintf(pack,"T1S%04d",cycle);
	if (strncmp(&desCompact[4],"T-2",3)==0) // Second Trojan Survey
	  sprintf(pack,"T2S%04d",cycle);
	if (strncmp(&desCompact[4],"T-3",3)==0) // Third Trojan Survey
	  sprintf(pack,"T3S%04d",cycle);
	pack[7]=0;
	return ;
      }

    if ((sscanf(desCompact,"%2d%2d%*2c%d",&cent,&year,&cycle)<3))
      cycle=0;
    //  printf("%s %d %d %d\n",Designation,cent,year,cycle);
    switch (cent)
      {
      case 18: pack[0]='I';  break;
      case 19: pack[0]='J';  break;
      case 20: pack[0]='K';  break;
      default: pack[0]='0'; /* printf("designation2pack: Wrong Designation\n"); */ return; break;  
      }
    char *ptr;
    ptr=pack; ptr++;
    sprintf(ptr,"%02d",year);
    ptr+=2;
    *ptr=desCompact[4];
    *++ptr=cycleLetter[cycle/10];
    *++ptr=cycleLetter[cycle%10];
    *++ptr=desCompact[5];
    *++ptr=0;
    return ;
  };

  void number2pack()
  {
    char Letter[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    
    if (Number<100000)
      sprintf(pack,"%05ld",Number);
    else
      {
	pack[0]=Letter[Number/10000-10];
	sprintf(&pack[1],"%04ld",Number % 10000);
      }
  };

  void line2pack(string line, int pos)
  {
    char *read = &line.at(pos);
    char *write=pack;
    int  isSurvey=0;
    int i;

    memset(pack,0,10); // reset pack;
    // the string might begin with spaces or some other shit
    // so run to the first good char but no more than 30
    for (i=0; i<30; i++)
      if (isalnum(*read++)) break;
    
    if (i>29) return; // jump out if 30 chars have been red and no good data been found.
    read--;
    
    do {
      if ((*read != ' ') && (*read != '_') && (isalnum(*read))) 
	*write++ = *read;
      if (*read == '-')
	isSurvey=1;
    } while (isalnum(*read++)); // until a non alpha numeric is found
  };

  void line2pack(string line)
  {
    line2pack(line,0);
  };

  void line2Designation(string line, int pos)
  {
    char *read = &line.at(pos);
    char *write=Designation;
    int  isSurvey=0;
    int i;

    memset(Designation,0,20); // reset Designation;
    // the string might begin with spaces or some other shit
    // so run to the first good char but no more than 30
    for (i=0; i<30; i++)
      if (isalnum(*read++)) break;
    
    if (i>29) return; // jump out if 30 chars have been red and no good data been found.
    read--;
    
    do {
      if ((*read != ' ') && (*read != '_') && (isalnum(*read))) 
	*write++ = *read;
      if (*read == '-')
	isSurvey=1;
    } while (isalnum(*read++)); // until a non alpha numeric is found

    
  };

  template<class T>
  long findUnnumberedAst(T *arr, long lastInd, long firstInd=0)
  {
    long ini=firstInd;
    long end=lastInd;
    long pivot = (end+ini)/2;
       
    long iter=0;
  
    while ((pivot-ini)>1)
    {
      if (*this==arr[pivot]) return pivot;
      if ((*this<arr[pivot]))
	end=pivot;
      else
	ini=pivot;
      pivot = (end+ini)/2;
      // cout << "iter= " << iter++ << " init= " << ini << " end= " << end << " pivot= " << pivot << " "; arr[pivot].print();
    }
  
    for(long j=ini; j<=end; j++)
      if (*this==arr[j]) return j;
    
    return -1;
  };

  template<class T>
  long match(T myAst[], long indLastMPC, long indLastNumbMPC, string* ids, long nIds)
  {
    long ind=-1;
    
    if (Number>0)
      {
	return Number-1;
      }
    else
      {
	// can you match is right there ?
	if ((ind = findUnnumberedAst(myAst,indLastMPC,indLastNumbMPC+1))>=0) // YES ! 
	  {
	    return ind;
	  }
	else
	  { // the designation could not be matched.
	    // try to see if the asteroid has been numbered LATER
	    ind=findId(ids,nIds);
	    if (ind<0)
	      return -1; // this is bad news as the string could not be matched
	    if (Number>0)
	      {
		return Number-1;
	      }
	    else
	      {
		if ((ind = findUnnumberedAst(myAst,indLastMPC,indLastNumbMPC+1))>=0) // YES ! 
		  {
		    return ind;
		  }
		else
		  {
		    return -1;
		  }
	      }
	  }
      }
  };

  // this is to be used to quick sort asteroids
  // comparison is done between Numbers at 1st level
  // number and non numberd with the former lower than the latter
  // and between the Designation in its compact form, i.e. with no spaces, no "_"
 
  int compare(const Asteroid *b)
  {
    Asteroid *a = this;

  // if both are numbered 
    if ((a->Number>0) && (b->Number>0))
      {
	if (a->Number > b->Number) return 1;
	else if (a->Number == b->Number) return 0;
	else return -1;
      }
  // if a is numbered but b is not
    if ((a->Number >0) && (b->Number<=0))
      return -1;
  // if b is numbered but a is not
    if ((a->Number<=0) && (b->Number>0))
      return 1;
   
  // if both are nunnumbered ONE must look at the designations
    if ((a->Number <= 0) && (b->Number <= 0) ) 
      {
	int ia, ib;
	sscanf(a->Designation,"%4d",&ia);
	sscanf(b->Designation,"%4d",&ib);
	if (ia>ib) return 1;
	if (ia<ib) return -1;
	// otherwise they have the same year
	if (a->Designation[4]>b->Designation[4]) return 1;
	if (a->Designation[4]<b->Designation[4]) return -1;
	//otherwise they have same year and same first letter
	if (a->Designation[5]>b->Designation[5]) return 1;
	if (a->Designation[5]<b->Designation[5]) return -1;
	// check if there is a number
	if ((a->Designation[6]==0) && (b->Designation[6]==0)) return 0;
	if ((a->Designation[6]==0) && (b->Designation[6]!=0)) return -1;
	if ((a->Designation[6]!=0) && (b->Designation[6]==0)) return 1;
	//otherwise they have same year, same first letter and same second letter !
	sscanf(&a->Designation[6],"%d",&ia);
	sscanf(&b->Designation[6],"%d",&ib);
	if (ia>ib) return 1;
	else if (ia<ib) return -1;
	else return 0;
      }
  };

  // overloaded < operator
  bool operator <(const Asteroid& b)
  {
    if (this->compare(&b)<0) return true;
    else return false;
  };
  // overloaded <= operator
  bool operator <=(const Asteroid& b)
  {
    if (this->compare(&b)<=0) return true;
    else return false;
  };
  
  // overloaded > operator
  bool operator >(const Asteroid& b)
  {
    if (this->compare(&b)>0) return true;
    else return false;
  };
  // overloaded >= operator
  bool operator >=(const Asteroid& b)
  {
    if (this->compare(&b)>=0) return true;
    else return false;
  };
  // overloaded == operator
  bool operator ==(const Asteroid& b)
  {
    if (this->compare(&b)==0) return true;
    else return false;
  };
  
  // overloaded = (ASSIGN) operator
  bool operator =(const Asteroid& b)
  {
    Number=b.Number;
    H=b.H;
    G=b.G;
    a=b.a;
    e=b.e;
    sini=b.sini;
    M=b.M;
    omega=b.omega;
    Omega=b.Omega;
    n=b.n;
    Epoch=b.Epoch;
    strcpy(Designation, b.Designation);
    strcpy(pack,b.pack);
    strcpy(EpochPack,b.EpochPack);
  };

  long findId(string* ids, long nIds)
  {
    long found=-1;

    //#pragma omp parallel
    {
      //#pragma omp parallel for shared(found)
      for (long i=0; i<nIds; i++)
	{
	  //	  if (found!= -1) continue;
	  found=ids[i].find(pack); // std::string.find
	  if (found!=std::string::npos)
	    {
	      if (ids[i].at(5)==' ') // this is from numids and the pack is a number
		{
		  strncpy(pack,&ids[i].at(0),5);
		  pack[5]=0;
		}
	      else
		{
		  strncpy(pack,&ids[i].at(0),7);	     
		  pack[7]=0;
		}
	      MPC2DesignationCompact(); 
	      return i;
	    }
	}
    }
    return -1;
  };

  void LC_sumString2Asteroid(string line)
  {
    char dummyStr[20];
    
    reset();
    strncpy(dummyStr,&line.at(0),8); dummyStr[8]=0;
    Number=atol(dummyStr);

    
        // remove spaces while copying designation string
    char *write = Designation;
    char *read = &line.at(41);
    int j=0;
    do {
      if ((*read != ' ') && (*read != '_'))
	*write++ = *read;
    } while ((*read++) && ((++j)<12));
    *write++ =0;
    Designation[12]=0;

    designation2pack();
    if (Number>0) number2pack();

    strncpy(dummyStr,&line.at(117),20); dummyStr[20]=0;
   
    rotationPeriod=atof(dummyStr);
  };

  void SourceRegionString2Asteroid(string line)
  {
    sscanf(&line.at(0),"%ld %s %lf %lf %lf\
%f %f %f %f %f %f %f", &Number, Designation, &a, &e, &sini,
	   &neaSourceRegion[0],&neaSourceRegion[1],&neaSourceRegion[2],&neaSourceRegion[3],
	   &neaSourceRegion[4],&neaSourceRegion[5],&neaSourceRegion[6]);

    if (Number<=0)
      designation2pack();
    else
      number2pack();
  };

  void resetNEAsSourceRegions(){
    for (int i=0; i<10; i++)
      neaSourceRegion[i]=-1;
  }
  
  void SourceRegionGranvikString2Asteroid(string line)
  {
    memset(Designation, 0, 20);
    sscanf(&line.at(0),"%s %f %lf %lf %lf\
%f %f %f %f %f %f %f", Designation, &H, &a, &e, &sini,
	   &neaSourceRegion[0],&neaSourceRegion[1],&neaSourceRegion[2],&neaSourceRegion[3],
	   &neaSourceRegion[4],&neaSourceRegion[5],&neaSourceRegion[6]);

    int isDesignation=0;
    for (int i=0; i<20; i++)
      {
	if (Designation[i]==0) break;
	if (isalpha(Designation[i])){
	  isDesignation=1;
	  break;
	}
      }

    designation2pack();

    if (isDesignation)
      {
	Number=-1;
      } else
      {
	Number = atol(Designation);
	memset(Designation, 0, 20);
      }  
  };

};
